home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / msdos / fileio.c < prev    next >
C/C++ Source or Header  |  2000-04-25  |  32KB  |  1,385 lines

  1. #include "mamalleg.h"
  2. #include "driver.h"
  3. #include "unzip.h"
  4. #include <sys/stat.h>
  5. #include <unistd.h>
  6. #include <signal.h>
  7.  
  8. #ifdef MESS
  9. #include "mess/msdos.h"
  10. #endif
  11.  
  12. /* Verbose outputs to error.log ? */
  13. #define VERBOSE     0
  14.  
  15. /* Use the file cache ? */
  16. #define FILE_CACHE    1
  17.  
  18. #if VERBOSE
  19. #define LOG(x)    logerror x
  20. #else
  21. #define LOG(x)    /* x */
  22. #endif
  23.  
  24. char *roms = NULL;
  25. char **rompathv = NULL;
  26. int rompathc = 0;
  27.  
  28. char *samples = NULL;
  29. char **samplepathv = NULL;
  30. int samplepathc = 0;
  31.  
  32. char *cfgdir, *nvdir, *hidir, *inpdir, *stadir;
  33. char *memcarddir, *artworkdir, *screenshotdir;
  34.  
  35. char *alternate_name;                   /* for "-romdir" */
  36.  
  37. typedef enum
  38. {
  39.     kPlainFile,
  40.     kRAMFile,
  41.     kZippedFile
  42. }    eFileType;
  43.  
  44. typedef struct
  45. {
  46.     FILE *file;
  47.     unsigned char *data;
  48.     unsigned int offset;
  49.     unsigned int length;
  50.     eFileType type;
  51.     unsigned int crc;
  52. }    FakeFileHandle;
  53.  
  54.  
  55. extern unsigned int crc32 (unsigned int crc, const unsigned char *buf, unsigned int len);
  56. static int checksum_file (const char *file, unsigned char **p, unsigned int *size, unsigned int *crc);
  57.  
  58. /*
  59.  * File stat cache LRU (Last Recently Used)
  60.  */
  61.  
  62. #if FILE_CACHE
  63. struct file_cache_entry
  64. {
  65.     struct stat stat_buffer;
  66.     int result;
  67.     char *file;
  68. };
  69.  
  70. /* File cache buffer */
  71. static struct file_cache_entry **file_cache_map = 0;
  72.  
  73. /* File cache size */
  74. static unsigned int file_cache_max = 0;
  75.  
  76. /* AM 980919 */
  77. static int cache_stat (const char *path, struct stat *statbuf)
  78. {
  79.     if( file_cache_max )
  80.     {
  81.         unsigned i;
  82.         struct file_cache_entry *entry;
  83.  
  84.         /* search in the cache */
  85.         for( i = 0; i < file_cache_max; ++i )
  86.         {
  87.             if( file_cache_map[i]->file && strcmp (file_cache_map[i]->file, path) == 0 )
  88.             {    /* found */
  89.                 unsigned j;
  90.  
  91. //                LOG(("File cache HIT  for %s\n", path));
  92.                 /* store */
  93.                 entry = file_cache_map[i];
  94.  
  95.                 /* shift */
  96.                 for( j = i; j > 0; --j )
  97.                     file_cache_map[j] = file_cache_map[j - 1];
  98.  
  99.                 /* set the first entry */
  100.                 file_cache_map[0] = entry;
  101.  
  102.                 if( entry->result == 0 )
  103.                     memcpy (statbuf, &entry->stat_buffer, sizeof (struct stat));
  104.  
  105.                 return entry->result;
  106.             }
  107.         }
  108. //        LOG(("File cache FAIL for %s\n", path));
  109.  
  110.         /* oldest entry */
  111.         entry = file_cache_map[file_cache_max - 1];
  112.         free (entry->file);
  113.  
  114.         /* shift */
  115.         for( i = file_cache_max - 1; i > 0; --i )
  116.             file_cache_map[i] = file_cache_map[i - 1];
  117.  
  118.         /* set the first entry */
  119.         file_cache_map[0] = entry;
  120.  
  121.         /* file */
  122.         entry->file = (char *) malloc (strlen (path) + 1);
  123.         strcpy (entry->file, path);
  124.  
  125.         /* result and stat */
  126.         entry->result = stat (path, &entry->stat_buffer);
  127.  
  128.         if( entry->result == 0 )
  129.             memcpy (statbuf, &entry->stat_buffer, sizeof (struct stat));
  130.  
  131.         return entry->result;
  132.     }
  133.     else
  134.     {
  135.         return stat (path, statbuf);
  136.     }
  137. }
  138.  
  139. /* AM 980919 */
  140. static void cache_allocate (unsigned entries)
  141. {
  142.     if( entries )
  143.     {
  144.         unsigned i;
  145.  
  146.         file_cache_max = entries;
  147.         file_cache_map = (struct file_cache_entry **) malloc (file_cache_max * sizeof (struct file_cache_entry *));
  148.  
  149.         for( i = 0; i < file_cache_max; ++i )
  150.         {
  151.             file_cache_map[i] = (struct file_cache_entry *) malloc (sizeof (struct file_cache_entry));
  152.             memset (file_cache_map[i], 0, sizeof (struct file_cache_entry));
  153.         }
  154.         LOG(("File cache allocated for %d entries\n", file_cache_max));
  155.     }
  156. }
  157. #else
  158.  
  159. #define cache_stat(a,b) stat(a,b)
  160.  
  161. #endif
  162.  
  163. /* This function can be called several times with different parameters,
  164.  * for example by "mame -verifyroms *". */
  165. void decompose_rom_sample_path (char *rompath, char *samplepath)
  166. {
  167.     char *token;
  168.  
  169.     /* start with zero path components */
  170.     rompathc = samplepathc = 0;
  171.  
  172.     if (!roms)
  173.         roms = malloc( strlen(rompath) + 1);
  174.     else
  175.         roms = realloc( roms, strlen(rompath) + 1);
  176.  
  177.     if (!samples)
  178.         samples = malloc( strlen(samplepath) + 1);
  179.     else
  180.         samples = realloc( samples, strlen(samplepath) + 1);
  181.  
  182.     if( !roms || !samples )
  183.     {
  184.         logerror("decompose_rom_sample_path: failed to malloc!\n");
  185.         raise(SIGABRT);
  186.     }
  187.  
  188.     strcpy (roms, rompath);
  189.     token = strtok (roms, ";");
  190.     while( token )
  191.     {
  192.         if( rompathc )
  193.             rompathv = realloc (rompathv, (rompathc + 1) * sizeof(char *));
  194.         else
  195.             rompathv = malloc (sizeof(char *));
  196.         if( !rompathv )
  197.             break;
  198.         rompathv[rompathc++] = token;
  199.         token = strtok (NULL, ";");
  200.     }
  201.  
  202.     strcpy (samples, samplepath);
  203.     token = strtok (samples, ";");
  204.     while( token )
  205.     {
  206.         if( samplepathc )
  207.             samplepathv = realloc (samplepathv, (samplepathc + 1) * sizeof(char *));
  208.         else
  209.             samplepathv = malloc (sizeof(char *));
  210.         if( !samplepathv )
  211.             break;
  212.         samplepathv[samplepathc++] = token;
  213.         token = strtok (NULL, ";");
  214.     }
  215.  
  216. #if FILE_CACHE
  217.     /* AM 980919 */
  218.     if( file_cache_max == 0 )
  219.     {
  220.         /* (rom path directories + 1 buffer)==rompathc+1 */
  221.         /* (dir + .zip + .zif)==3 */
  222.         /* (clone+parent)==2 */
  223.         cache_allocate ((rompathc + 1) * 3 * 2);
  224.     }
  225. #endif
  226.  
  227. }
  228.  
  229. /*
  230.  * file handling routines
  231.  *
  232.  * gamename holds the driver name, filename is only used for ROMs and samples.
  233.  * if 'write' is not 0, the file is opened for write. Otherwise it is opened
  234.  * for read.
  235.  */
  236.  
  237. /*
  238.  * check if roms/samples for a game exist at all
  239.  * return index+1 of the path vector component on success, otherwise 0
  240.  */
  241. int osd_faccess (const char *newfilename, int filetype)
  242. {
  243.     static int indx;
  244.     static const char *filename;
  245.     char name[256];
  246.     char **pathv;
  247.     int pathc;
  248.     char *dir_name;
  249.  
  250.     /* if filename == NULL, continue the search */
  251.     if( newfilename != NULL )
  252.     {
  253.         indx = 0;
  254.         filename = newfilename;
  255.     }
  256.     else
  257.         indx++;
  258.  
  259. #ifdef MESS
  260.     if( filetype == OSD_FILETYPE_ROM ||
  261.         filetype == OSD_FILETYPE_IMAGE_R ||
  262.         filetype == OSD_FILETYPE_IMAGE_RW )
  263. #else
  264.     if( filetype == OSD_FILETYPE_ROM )
  265. #endif
  266.     {
  267.         pathv = rompathv;
  268.         pathc = rompathc;
  269.     }
  270.     else
  271.     if( filetype == OSD_FILETYPE_SAMPLE )
  272.     {
  273.         pathv = samplepathv;
  274.         pathc = samplepathc;
  275.     }
  276.     else
  277.     if( filetype == OSD_FILETYPE_SCREENSHOT )
  278.     {
  279.         void *f;
  280.  
  281.         sprintf (name, "%s/%s.png", screenshotdir, newfilename);
  282.         f = fopen (name, "rb");
  283.         if( f )
  284.         {
  285.             fclose (f);
  286.             return 1;
  287.         }
  288.         else
  289.             return 0;
  290.     }
  291.     else
  292.         return 0;
  293.  
  294.     for( ; indx < pathc; indx++ )
  295.     {
  296.         struct stat stat_buffer;
  297.  
  298.         dir_name = pathv[indx];
  299.  
  300.         /* does such a directory (or file) exist? */
  301.         sprintf (name, "%s/%s", dir_name, filename);
  302.         if( cache_stat (name, &stat_buffer) == 0 )
  303.             return indx + 1;
  304.  
  305.         /* try again with a .zip extension */
  306.         sprintf (name, "%s/%s.zip", dir_name, filename);
  307.         if( cache_stat (name, &stat_buffer) == 0 )
  308.             return indx + 1;
  309.  
  310.         /* try again with a .zif extension */
  311.         sprintf (name, "%s/%s.zif", dir_name, filename);
  312.         if( cache_stat (name, &stat_buffer) == 0 )
  313.             return indx + 1;
  314.     }
  315.  
  316.     /* no match */
  317.     return 0;
  318. }
  319.  
  320. /* JB 980920 update */
  321. /* AM 980919 update */
  322. void *osd_fopen (const char *game, const char *filename, int filetype, int _write)
  323. {
  324.     char name[256];
  325.     char *gamename;
  326.     int found = 0;
  327.     int indx;
  328.     struct stat stat_buffer;
  329.     FakeFileHandle *f;
  330.     int pathc;
  331.     char **pathv;
  332.  
  333.  
  334.     f = (FakeFileHandle *) malloc (sizeof (FakeFileHandle));
  335.     if( !f )
  336.     {
  337.         logerror("osd_fopen: failed to malloc FakeFileHandle!\n");
  338.         return 0;
  339.     }
  340.     memset (f, 0, sizeof (FakeFileHandle));
  341.  
  342.     gamename = (char *) game;
  343.  
  344.     /* Support "-romdir" yuck. */
  345.     if( alternate_name )
  346.     {
  347.         LOG(("osd_fopen: -romdir overrides '%s' by '%s'\n", gamename, alternate_name));
  348.         gamename = alternate_name;
  349.     }
  350.  
  351.     switch( filetype )
  352.     {
  353.     case OSD_FILETYPE_ROM:
  354.     case OSD_FILETYPE_SAMPLE:
  355.  
  356.         /* only for reading */
  357.         if( _write )
  358.         {
  359.             logerror("osd_fopen: type %02x write not supported\n",filetype);
  360.             break;
  361.         }
  362.  
  363.         if( filetype == OSD_FILETYPE_SAMPLE )
  364.         {
  365.             LOG(("osd_fopen: using samplepath\n"));
  366.             pathc = samplepathc;
  367.             pathv = samplepathv;
  368.         }
  369.         else
  370.         {
  371.             LOG(("osd_fopen: using rompath\n"));
  372.             pathc = rompathc;
  373.             pathv = rompathv;
  374.         }
  375.  
  376.         for( indx = 0; indx < pathc && !found; ++indx )
  377.         {
  378.             const char *dir_name = pathv[indx];
  379.  
  380.             if( !found )
  381.             {
  382.                 sprintf (name, "%s/%s", dir_name, gamename);
  383.                 LOG(("Trying %s\n", name));
  384.                 if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  385.                 {
  386.                     sprintf (name, "%s/%s/%s", dir_name, gamename, filename);
  387.                     if( filetype == OSD_FILETYPE_ROM )
  388.                     {
  389.                         if( checksum_file (name, &f->data, &f->length, &f->crc) == 0 )
  390.                         {
  391.                             f->type = kRAMFile;
  392.                             f->offset = 0;
  393.                             found = 1;
  394.                         }
  395.                     }
  396.                     else
  397.                     {
  398.                         f->type = kPlainFile;
  399.                         f->file = fopen (name, "rb");
  400.                         found = f->file != 0;
  401.                     }
  402.                 }
  403.             }
  404.  
  405.             if( !found )
  406.             {
  407.                 /* try with a .zip extension */
  408.                 sprintf (name, "%s/%s.zip", dir_name, gamename);
  409.                 LOG(("Trying %s file\n", name));
  410.                 if( cache_stat (name, &stat_buffer) == 0 )
  411.                 {
  412.                     if( load_zipped_file (name, filename, &f->data, &f->length) == 0 )
  413.                     {
  414.                         LOG(("Using (osd_fopen) zip file for %s\n", filename));
  415.                         f->type = kZippedFile;
  416.                         f->offset = 0;
  417.                         f->crc = crc32 (0L, f->data, f->length);
  418.                         found = 1;
  419.                     }
  420.                 }
  421.             }
  422.  
  423.             if( !found )
  424.             {
  425.                 /* try with a .zip directory (if ZipMagic is installed) */
  426.                 sprintf (name, "%s/%s.zip", dir_name, gamename);
  427.                 LOG(("Trying %s directory\n", name));
  428.                 if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  429.                 {
  430.                     sprintf (name, "%s/%s.zip/%s", dir_name, gamename, filename);
  431.                     if( filetype == OSD_FILETYPE_ROM )
  432.                     {
  433.                         if( checksum_file (name, &f->data, &f->length, &f->crc) == 0 )
  434.                         {
  435.                             f->type = kRAMFile;
  436.                             f->offset = 0;
  437.                             found = 1;
  438.                         }
  439.                     }
  440.                     else
  441.                     {
  442.                         f->type = kPlainFile;
  443.                         f->file = fopen (name, "rb");
  444.                         found = f->file != 0;
  445.                     }
  446.                 }
  447.             }
  448.         }
  449.  
  450.         break;
  451.  
  452. #ifdef MESS
  453.     case OSD_FILETYPE_IMAGE_R:
  454.  
  455.         /* only for reading */
  456.         if( _write )
  457.         {
  458.             logerror("osd_fopen: type %02x write not supported\n",filetype);
  459.             break;
  460.         }
  461.         else
  462.         {
  463.             LOG(("osd_fopen: using rompath\n"));
  464.             pathc = rompathc;
  465.             pathv = rompathv;
  466.         }
  467.  
  468.         LOG(("Open IMAGE_R '%s' for %s\n", filename, game));
  469.         for( indx = 0; indx < pathc && !found; ++indx )
  470.         {
  471.             const char *dir_name = pathv[indx];
  472.  
  473.             /* this section allows exact path from .cfg */
  474.             if( !found )
  475.             {
  476.                 sprintf(name,"%s",dir_name);
  477.                 if( cache_stat(name,&stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  478.                 {
  479.                     sprintf(name,"%s/%s",dir_name,filename);
  480.                     if( filetype == OSD_FILETYPE_ROM )
  481.                     {
  482.                         if( checksum_file (name, &f->data, &f->length, &f->crc) == 0 )
  483.                         {
  484.                             f->type = kRAMFile;
  485.                             f->offset = 0;
  486.                             found = 1;
  487.                         }
  488.                     }
  489.                     else
  490.                     {
  491.                         f->type = kPlainFile;
  492.                         f->file = fopen(name,"rb");
  493.                         found = f->file!=0;
  494.                     }
  495.                 }
  496.             }
  497.  
  498.             if( !found )
  499.             {
  500.                 sprintf (name, "%s/%s", dir_name, gamename);
  501.                 LOG(("Trying %s directory\n", name));
  502.                 if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  503.                 {
  504.                     sprintf (name, "%s/%s/%s", dir_name, gamename, filename);
  505.                     LOG(("Trying %s file\n", name));
  506.                     if( filetype == OSD_FILETYPE_ROM )
  507.                     {
  508.                         if( checksum_file(name, &f->data, &f->length, &f->crc) == 0 )
  509.                         {
  510.                             f->type = kRAMFile;
  511.                             f->offset = 0;
  512.                             found = 1;
  513.                         }
  514.                     }
  515.                     else
  516.                     {
  517.                         f->type = kPlainFile;
  518.                         f->file = fopen (name, "rb");
  519.                         found = f->file != 0;
  520.                     }
  521.                 }
  522.             }
  523.  
  524.             /* Zip cart support for MESS */
  525.             if( !found && filetype == OSD_FILETYPE_IMAGE_R )
  526.             {
  527.                 char *extension = strrchr (name, '.');    /* find extension */
  528.                 if( extension )
  529.                     strcpy (extension, ".zip");
  530.                 else
  531.                     strcat (name, ".zip");
  532.                 LOG(("Trying %s file\n", name));
  533.                 if( cache_stat(name, &stat_buffer) == 0 )
  534.                 {
  535.                     if( load_zipped_file(name, filename, &f->data, &f->length) == 0 )
  536.                     {
  537.                         LOG(("Using (osd_fopen) zip file for %s\n", filename));
  538.                         f->type = kZippedFile;
  539.                         f->offset = 0;
  540.                         f->crc = crc32 (0L, f->data, f->length);
  541.                         found = 1;
  542.                     }
  543.                 }
  544.             }
  545.  
  546.             if( !found )
  547.             {
  548.                 /* try with a .zip extension */
  549.                 sprintf (name, "%s/%s.zip", dir_name, gamename);
  550.                 LOG(("Trying %s file\n", name));
  551.                 if( cache_stat(name, &stat_buffer) == 0 )
  552.                 {
  553.                     if( load_zipped_file(name, filename, &f->data, &f->length) == 0 )
  554.                     {
  555.                         LOG(("Using (osd_fopen) zip file for %s\n", filename));
  556.                         f->type = kZippedFile;
  557.                         f->offset = 0;
  558.                         f->crc = crc32 (0L, f->data, f->length);
  559.                         found = 1;
  560.                     }
  561.                 }
  562.             }
  563.         }
  564.     break; /* end of IMAGE_R */
  565.  
  566.     case OSD_FILETYPE_IMAGE_RW:
  567.         {
  568.             static char *write_modes[] = {"rb","wb","r+b","r+b","w+b"};
  569.             char file[256];
  570.             char *extension;
  571.  
  572.             LOG(("Open IMAGE_RW '%s' for %s mode '%s'\n", filename, game, write_modes[_write]));
  573.             strcpy (file, filename);
  574.  
  575.             do
  576.             {
  577.                 for( indx = 0; indx < rompathc && !found; ++indx )
  578.                 {
  579.                     const char *dir_name = rompathv[indx];
  580.  
  581.                     /* Exact path support */
  582.                     if (!found)
  583.                     {
  584.                         sprintf(name, "%s", dir_name);
  585.                         LOG(("Trying %s directory\n", name));
  586.                         if( cache_stat(name,&stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  587.                         {
  588.                             sprintf(name,"%s/%s", dir_name, file);
  589.                             LOG(("Trying %s file\n", name));
  590.                             f->file = fopen(name, write_modes[_write]);
  591.                             found = f->file != 0;
  592.                             if( !found && _write == 3 )
  593.                             {
  594.                                 f->file = fopen(name, write_modes[4]);
  595.                                 found = f->file != 0;
  596.                             }
  597.                         }
  598.                     }
  599.  
  600.                     if( !found )
  601.                     {
  602.                         sprintf (name, "%s/%s", dir_name, gamename);
  603.                         LOG(("Trying %s directory\n", name));
  604.                         if( cache_stat(name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  605.                         {
  606.                             sprintf (name, "%s/%s/%s", dir_name, gamename, file);
  607.                             LOG(("Trying %s file\n", name));
  608.                             f->file = fopen (name, write_modes[_write]);
  609.                             found = f->file != 0;
  610.                             if( !found && _write == 3 )
  611.                             {
  612.                                 f->file = fopen(name, write_modes[4]);
  613.                                 found = f->file != 0;
  614.                             }
  615.                         }
  616.                     }
  617.  
  618.                     if( !found && !_write )
  619.                     {
  620.                         extension = strrchr (name, '.');    /* find extension */
  621.                         /* add .zip for zipfile */
  622.                         if( extension )
  623.                             strcpy(extension, ".zip");
  624.                         else
  625.                             strcat(extension, ".zip");
  626.                         LOG(("Trying %s file\n", name));
  627.                         if( cache_stat(name, &stat_buffer) == 0 )
  628.                         {
  629.                             if( load_zipped_file(name, filename, &f->data, &f->length) == 0 )
  630.                             {
  631.                                 LOG(("Using (osd_fopen) zip file for %s\n", filename));
  632.                                 f->type = kZippedFile;
  633.                                 f->offset = 0;
  634.                                 f->crc = crc32(0L, f->data, f->length);
  635.                                 found = 1;
  636.                             }
  637.                         }
  638.                     }
  639.  
  640.                     if( !found && !_write )
  641.                     {
  642.                         /* try with a .zip extension */
  643.                         sprintf (name, "%s/%s.zip", dir_name, gamename);
  644.                         LOG(("Trying %s file\n", name));
  645.                         if( cache_stat (name, &stat_buffer) == 0 )
  646.                         {
  647.                             if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
  648.                             {
  649.                                 LOG(("Using (osd_fopen) zip file for %s\n", filename));
  650.                                 f->type = kZippedFile;
  651.                                 f->offset = 0;
  652.                                 f->crc = crc32 (0L, f->data, f->length);
  653.                                 found = 1;
  654.                             }
  655.                         }
  656.                     }
  657.  
  658.                     if( !found )
  659.                     {
  660.                         /* try with a .zip directory (if ZipMagic is installed) */
  661.                         sprintf (name, "%s/%s.zip", dir_name, gamename);
  662.                         LOG(("Trying %s ZipMagic directory\n", name));
  663.                         if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  664.                         {
  665.                             sprintf (name, "%s/%s.zip/%s", dir_name, gamename, file);
  666.                             LOG(("Trying %s\n", name));
  667.                             f->file = fopen (name, write_modes[_write]);
  668.                             found = f->file != 0;
  669.                             if( !found && _write == 3 )
  670.                             {
  671.                                 f->file = fopen(name, write_modes[4]);
  672.                                 found = f->file != 0;
  673.                             }
  674.                         }
  675.                     }
  676.                     if( found )
  677.                         LOG(("IMAGE_RW %s FOUND in %s!\n", file, name));
  678.                 }
  679.  
  680.                 extension = strrchr (file, '.');
  681.                 if( extension )
  682.                     *extension = '\0';
  683.             } while( !found && extension );
  684.         }
  685.         break;
  686. #endif    /* MESS */
  687.  
  688.  
  689.     case OSD_FILETYPE_NVRAM:
  690.         if( !found )
  691.         {
  692.             sprintf (name, "%s/%s.nv", nvdir, gamename);
  693.             f->type = kPlainFile;
  694.             f->file = fopen (name, _write ? "wb" : "rb");
  695.             found = f->file != 0;
  696.         }
  697.  
  698.         if( !found )
  699.         {
  700.             /* try with a .zip directory (if ZipMagic is installed) */
  701.             sprintf (name, "%s.zip/%s.nv", nvdir, gamename);
  702.             f->type = kPlainFile;
  703.             f->file = fopen (name, _write ? "wb" : "rb");
  704.             found = f->file != 0;
  705.         }
  706.  
  707.         if( !found )
  708.         {
  709.             /* try with a .zif directory (if ZipFolders is installed) */
  710.             sprintf (name, "%s.zif/%s.nv", nvdir, gamename);
  711.             f->type = kPlainFile;
  712.             f->file = fopen (name, _write ? "wb" : "rb");
  713.             found = f->file != 0;
  714.         }
  715.         break;
  716.  
  717.     case OSD_FILETYPE_HIGHSCORE:
  718.         if( mame_highscore_enabled () )
  719.         {
  720.             if( !found )
  721.             {
  722.                 sprintf (name, "%s/%s.hi", hidir, gamename);
  723.                 f->type = kPlainFile;
  724.                 f->file = fopen (name, _write ? "wb" : "rb");
  725.                 found = f->file != 0;
  726.             }
  727.  
  728.             if( !found )
  729.             {
  730.                 /* try with a .zip directory (if ZipMagic is installed) */
  731.                 sprintf (name, "%s.zip/%s.hi", hidir, gamename);
  732.                 f->type = kPlainFile;
  733.                 f->file = fopen (name, _write ? "wb" : "rb");
  734.                 found = f->file != 0;
  735.             }
  736.  
  737.             if( !found )
  738.             {
  739.                 /* try with a .zif directory (if ZipFolders is installed) */
  740.                 sprintf (name, "%s.zif/%s.hi", hidir, gamename);
  741.                 f->type = kPlainFile;
  742.                 f->file = fopen (name, _write ? "wb" : "rb");
  743.                 found = f->file != 0;
  744.             }
  745.         }
  746.         break;
  747.  
  748.     case OSD_FILETYPE_CONFIG:
  749.         sprintf (name, "%s/%s.cfg", cfgdir, gamename);
  750.         f->type = kPlainFile;
  751.         f->file = fopen (name, _write ? "wb" : "rb");
  752.         found = f->file != 0;
  753.  
  754.         if( !found )
  755.         {
  756.             /* try with a .zip directory (if ZipMagic is installed) */
  757.             sprintf (name, "%s.zip/%s.cfg", cfgdir, gamename);
  758.             f->type = kPlainFile;
  759.             f->file = fopen (name, _write ? "wb" : "rb");
  760.             found = f->file != 0;
  761.         }
  762.  
  763.         if( !found )
  764.         {
  765.             /* try with a .zif directory (if ZipFolders is installed) */
  766.             sprintf (name, "%s.zif/%s.cfg", cfgdir, gamename);
  767.             f->type = kPlainFile;
  768.             f->file = fopen (name, _write ? "wb" : "rb");
  769.             found = f->file != 0;
  770.         }
  771.         break;
  772.  
  773.     case OSD_FILETYPE_INPUTLOG:
  774.         sprintf (name, "%s/%s.inp", inpdir, gamename);
  775.         f->type = kPlainFile;
  776.         f->file = fopen (name, _write ? "wb" : "rb");
  777.         found = f->file != 0;
  778.  
  779.         if( !found )
  780.         {
  781.             /* try with a .zip directory (if ZipMagic is installed) */
  782.             sprintf (name, "%s.zip/%s.cfg", inpdir, gamename);
  783.             f->type = kPlainFile;
  784.             f->file = fopen (name, _write ? "wb" : "rb");
  785.             found = f->file != 0;
  786.         }
  787.  
  788.         if( !found )
  789.         {
  790.             /* try with a .zif directory (if ZipFolders is installed) */
  791.             sprintf (name, "%s.zif/%s.cfg", inpdir, gamename);
  792.             f->type = kPlainFile;
  793.             f->file = fopen (name, _write ? "wb" : "rb");
  794.             found = f->file != 0;
  795.         }
  796.  
  797.         if( !_write )
  798.         {
  799.             char file[256];
  800.             sprintf (file, "%s.inp", gamename);
  801.             sprintf (name, "%s/%s.zip", inpdir, gamename);
  802.             LOG(("Trying %s in %s\n", file, name));
  803.             if( cache_stat (name, &stat_buffer) == 0 )
  804.             {
  805.                 if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
  806.                 {
  807.                     LOG(("Using (osd_fopen) zip file %s for %s\n", name, file));
  808.                     f->type = kZippedFile;
  809.                     f->offset = 0;
  810.                     found = 1;
  811.                 }
  812.             }
  813.         }
  814.  
  815.         break;
  816.  
  817.     case OSD_FILETYPE_STATE:
  818.         sprintf (name, "%s/%s.sta", stadir, gamename);
  819.         f->file = fopen (name, _write ? "wb" : "rb");
  820.         found = !(f->file == 0);
  821.         if( !found )
  822.         {
  823.             /* try with a .zip directory (if ZipMagic is installed) */
  824.             sprintf (name, "%s.zip/%s.sta", stadir, gamename);
  825.             f->file = fopen (name, _write ? "wb" : "rb");
  826.             found = !(f->file == 0);
  827.         }
  828.         if( !found )
  829.         {
  830.             /* try with a .zif directory (if ZipFolders is installed) */
  831.             sprintf (name, "%s.zif/%s.sta", stadir, gamename);
  832.             f->file = fopen (name, _write ? "wb" : "rb");
  833.             found = !(f->file == 0);
  834.         }
  835.         break;
  836.  
  837.     case OSD_FILETYPE_ARTWORK:
  838.         /* only for reading */
  839.         if( _write )
  840.         {
  841.             logerror("osd_fopen: type %02x write not supported\n",filetype);
  842.             break;
  843.         }
  844.         sprintf (name, "%s/%s", artworkdir, filename);
  845.         f->type = kPlainFile;
  846.         f->file = fopen (name, _write ? "wb" : "rb");
  847.         found = f->file != 0;
  848.         if( !found )
  849.         {
  850.             /* try with a .zip directory (if ZipMagic is installed) */
  851.             sprintf (name, "%s.zip/%s.png", artworkdir, filename);
  852.             f->type = kPlainFile;
  853.             f->file = fopen (name, _write ? "wb" : "rb");
  854.             found = f->file != 0;
  855.         }
  856.  
  857.         if( !found )
  858.         {
  859.             /* try with a .zif directory (if ZipFolders is installed) */
  860.             sprintf (name, "%s.zif/%s.png", artworkdir, filename);
  861.             f->type = kPlainFile;
  862.             f->file = fopen (name, _write ? "wb" : "rb");
  863.             found = f->file != 0;
  864.         }
  865.  
  866.         if( !found )
  867.         {
  868.             char file[256], *extension;
  869.             sprintf(file, "%s", filename);
  870.             sprintf(name, "%s/%s", artworkdir, filename);
  871.             extension = strrchr(name, '.');
  872.             if( extension )
  873.                 strcpy (extension, ".zip");
  874.             else
  875.                 strcat (name, ".zip");
  876.             LOG(("Trying %s in %s\n", file, name));
  877.             if( cache_stat (name, &stat_buffer) == 0 )
  878.             {
  879.                 if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
  880.                 {
  881.                     LOG(("Using (osd_fopen) zip file %s\n", name));
  882.                     f->type = kZippedFile;
  883.                     f->offset = 0;
  884.                     found = 1;
  885.                 }
  886.             }
  887.             if( !found )
  888.             {
  889.                 sprintf(name, "%s/%s.zip", artworkdir, game);
  890.                 LOG(("Trying %s in %s\n", file, name));
  891.                 if( cache_stat (name, &stat_buffer) == 0 )
  892.                 {
  893.                     if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
  894.                     {
  895.                         LOG(("Using (osd_fopen) zip file %s\n", name));
  896.                         f->type = kZippedFile;
  897.                         f->offset = 0;
  898.                         found = 1;
  899.                     }
  900.                 }
  901.             }
  902.         }
  903.         break;
  904.  
  905.     case OSD_FILETYPE_MEMCARD:
  906.         sprintf (name, "%s/%s", memcarddir, filename);
  907.         f->type = kPlainFile;
  908.         f->file = fopen (name, _write ? "wb" : "rb");
  909.         found = f->file != 0;
  910.         break;
  911.  
  912.     case OSD_FILETYPE_SCREENSHOT:
  913.         /* only for writing */
  914.         if( !_write )
  915.         {
  916.             logerror("osd_fopen: type %02x read not supported\n",filetype);
  917.             break;
  918.         }
  919.  
  920.         sprintf (name, "%s/%s.png", screenshotdir, filename);
  921.         f->type = kPlainFile;
  922.         f->file = fopen (name, _write ? "wb" : "rb");
  923.         found = f->file != 0;
  924.         break;
  925.  
  926.     case OSD_FILETYPE_HIGHSCORE_DB:
  927.     case OSD_FILETYPE_HISTORY:
  928.     case OSD_FILETYPE_CHEAT:
  929.         /* only for reading */
  930.         if( _write )
  931.         {
  932.             logerror("osd_fopen: type %02x write not supported\n",filetype);
  933.             break;
  934.         }
  935.         f->type = kPlainFile;
  936.         /* open as ASCII files, not binary like the others */
  937.         f->file = fopen (filename, _write ? "w" : "r");
  938.         found = f->file != 0;
  939.         break;
  940.  
  941.     case OSD_FILETYPE_LANGUAGE:
  942.         /* only for reading */
  943.         if( _write )
  944.         {
  945.             logerror("osd_fopen: type %02x write not supported\n",filetype);
  946.             break;
  947.         }
  948.         sprintf (name, "%s.lng", filename);
  949.         f->type = kPlainFile;
  950.         /* open as ASCII files, not binary like the others */
  951.         f->file = fopen (name, _write ? "w" : "r");
  952.         found = f->file != 0;
  953. logerror("fopen %s = %08x\n",name,(int)f->file);
  954.         break;
  955.  
  956.     default:
  957.         logerror("osd_fopen(): unknown filetype %02x\n",filetype);
  958.     }
  959.  
  960.     if( !found )
  961.     {
  962.         free (f);
  963.         return 0;
  964.     }
  965.  
  966.     return f;
  967. }
  968.  
  969. /* JB 980920 update */
  970. int osd_fread (void *file, void *buffer, int length)
  971. {
  972.     FakeFileHandle *f = (FakeFileHandle *) file;
  973.  
  974.     switch( f->type )
  975.     {
  976.     case kPlainFile:
  977.         return fread (buffer, 1, length, f->file);
  978.         break;
  979.     case kZippedFile:
  980.     case kRAMFile:
  981.         /* reading from the RAM image of a file */
  982.         if( f->data )
  983.         {
  984.             if( length + f->offset > f->length )
  985.                 length = f->length - f->offset;
  986.             memcpy (buffer, f->offset + f->data, length);
  987.             f->offset += length;
  988.             return length;
  989.         }
  990.         break;
  991.     }
  992.  
  993.     return 0;
  994. }
  995.  
  996. int osd_fread_swap (void *file, void *buffer, int length)
  997. {
  998.     int i;
  999.     unsigned char *buf;
  1000.     unsigned char temp;
  1001.     int res;
  1002.  
  1003.  
  1004.     res = osd_fread (file, buffer, length);
  1005.  
  1006.     buf = buffer;
  1007.     for( i = 0; i < length; i += 2 )
  1008.     {
  1009.         temp = buf[i];
  1010.         buf[i] = buf[i + 1];
  1011.         buf[i + 1] = temp;
  1012.     }
  1013.  
  1014.     return res;
  1015. }
  1016.  
  1017.  
  1018. /* AM 980919 update */
  1019. int osd_fwrite (void *file, const void *buffer, int length)
  1020. {
  1021.     FakeFileHandle *f = (FakeFileHandle *) file;
  1022.  
  1023.     switch( f->type )
  1024.     {
  1025.     case kPlainFile:
  1026.         return fwrite (buffer, 1, length, ((FakeFileHandle *) file)->file);
  1027.     default:
  1028.         return 0;
  1029.     }
  1030. }
  1031.  
  1032. int osd_fwrite_swap (void *file, const void *buffer, int length)
  1033. {
  1034.     int i;
  1035.     unsigned char *buf;
  1036.     unsigned char temp;
  1037.     int res;
  1038.  
  1039.  
  1040.     buf = (unsigned char *) buffer;
  1041.     for( i = 0; i < length; i += 2 )
  1042.     {
  1043.         temp = buf[i];
  1044.         buf[i] = buf[i + 1];
  1045.         buf[i + 1] = temp;
  1046.     }
  1047.  
  1048.     res = osd_fwrite (file, buffer, length);
  1049.  
  1050.     for( i = 0; i < length; i += 2 )
  1051.     {
  1052.         temp = buf[i];
  1053.         buf[i] = buf[i + 1];
  1054.         buf[i + 1] = temp;
  1055.     }
  1056.  
  1057.     return res;
  1058. }
  1059.  
  1060. int osd_fread_scatter (void *file, void *buffer, int length, int increment)
  1061. {
  1062.     unsigned char *buf = buffer;
  1063.     FakeFileHandle *f = (FakeFileHandle *) file;
  1064.     unsigned char tempbuf[4096];
  1065.     int totread, r, i;
  1066.  
  1067.     switch( f->type )
  1068.     {
  1069.     case kPlainFile:
  1070.         totread = 0;
  1071.         while (length)
  1072.         {
  1073.             r = length;
  1074.             if( r > 4096 )
  1075.                 r = 4096;
  1076.             r = fread (tempbuf, 1, r, f->file);
  1077.             if( r == 0 )
  1078.                 return totread;           /* error */
  1079.             for( i = 0; i < r; i++ )
  1080.             {
  1081.                 *buf = tempbuf[i];
  1082.                 buf += increment;
  1083.             }
  1084.             totread += r;
  1085.             length -= r;
  1086.         }
  1087.         return totread;
  1088.         break;
  1089.     case kZippedFile:
  1090.     case kRAMFile:
  1091.         /* reading from the RAM image of a file */
  1092.         if( f->data )
  1093.         {
  1094.             if( length + f->offset > f->length )
  1095.                 length = f->length - f->offset;
  1096.             for( i = 0; i < length; i++ )
  1097.             {
  1098.                 *buf = f->data[f->offset + i];
  1099.                 buf += increment;
  1100.             }
  1101.             f->offset += length;
  1102.             return length;
  1103.         }
  1104.         break;
  1105.     }
  1106.  
  1107.     return 0;
  1108. }
  1109.  
  1110.  
  1111. /* JB 980920 update */
  1112. int osd_fseek (void *file, int offset, int whence)
  1113. {
  1114.     FakeFileHandle *f = (FakeFileHandle *) file;
  1115.     int err = 0;
  1116.  
  1117.     switch( f->type )
  1118.     {
  1119.     case kPlainFile:
  1120.         return fseek (f->file, offset, whence);
  1121.         break;
  1122.     case kZippedFile:
  1123.     case kRAMFile:
  1124.         /* seeking within the RAM image of a file */
  1125.         switch( whence )
  1126.         {
  1127.         case SEEK_SET:
  1128.             f->offset = offset;
  1129.             break;
  1130.         case SEEK_CUR:
  1131.             f->offset += offset;
  1132.             break;
  1133.         case SEEK_END:
  1134.             f->offset = f->length + offset;
  1135.             break;
  1136.         }
  1137.         break;
  1138.     }
  1139.  
  1140.     return err;
  1141. }
  1142.  
  1143. /* JB 980920 update */
  1144. void osd_fclose (void *file)
  1145. {
  1146.     FakeFileHandle *f = (FakeFileHandle *) file;
  1147.  
  1148.     switch( f->type )
  1149.     {
  1150.     case kPlainFile:
  1151.         fclose (f->file);
  1152.         break;
  1153.     case kZippedFile:
  1154.     case kRAMFile:
  1155.         if( f->data )
  1156.             free (f->data);
  1157.         break;
  1158.     }
  1159.     free (f);
  1160. }
  1161.  
  1162. /* JB 980920 update */
  1163. /* AM 980919 */
  1164. static int checksum_file (const char *file, unsigned char **p, unsigned int *size, unsigned int *crc)
  1165. {
  1166.     int length;
  1167.     unsigned char *data;
  1168.     FILE *f;
  1169.  
  1170.     f = fopen (file, "rb");
  1171.     if( !f )
  1172.         return -1;
  1173.  
  1174.     /* determine length of file */
  1175.     if( fseek (f, 0L, SEEK_END) != 0 )
  1176.     {
  1177.         fclose (f);
  1178.         return -1;
  1179.     }
  1180.  
  1181.     length = ftell (f);
  1182.     if( length == -1L )
  1183.     {
  1184.         fclose (f);
  1185.         return -1;
  1186.     }
  1187.  
  1188.     /* allocate space for entire file */
  1189.     data = (unsigned char *) malloc (length);
  1190.     if( !data )
  1191.     {
  1192.         fclose (f);
  1193.         return -1;
  1194.     }
  1195.  
  1196.     /* read entire file into memory */
  1197.     if( fseek (f, 0L, SEEK_SET) != 0 )
  1198.     {
  1199.         free (data);
  1200.         fclose (f);
  1201.         return -1;
  1202.     }
  1203.  
  1204.     if( fread (data, sizeof (unsigned char), length, f) != length )
  1205.     {
  1206.         free (data);
  1207.         fclose (f);
  1208.         return -1;
  1209.     }
  1210.  
  1211.     *size = length;
  1212.     *crc = crc32 (0L, data, length);
  1213.     if( p )
  1214.         *p = data;
  1215.     else
  1216.         free (data);
  1217.  
  1218.     fclose (f);
  1219.  
  1220.     return 0;
  1221. }
  1222.  
  1223. /* JB 980920 updated */
  1224. /* AM 980919 updated */
  1225. int osd_fchecksum (const char *game, const char *filename, unsigned int *length, unsigned int *sum)
  1226. {
  1227.     char name[256];
  1228.     int indx;
  1229.     struct stat stat_buffer;
  1230.     int found = 0;
  1231.     const char *gamename = game;
  1232.  
  1233.     /* Support "-romdir" yuck. */
  1234.     if( alternate_name )
  1235.         gamename = alternate_name;
  1236.  
  1237.     for( indx = 0; indx < rompathc && !found; ++indx )
  1238.     {
  1239.         const char *dir_name = rompathv[indx];
  1240.  
  1241.         if( !found )
  1242.         {
  1243.             sprintf (name, "%s/%s", dir_name, gamename);
  1244.             if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
  1245.             {
  1246.                 sprintf (name, "%s/%s/%s", dir_name, gamename, filename);
  1247.                 if( checksum_file (name, 0, length, sum) == 0 )
  1248.                 {
  1249.                     found = 1;
  1250.                 }
  1251.             }
  1252.         }
  1253.  
  1254.         if( !found )
  1255.         {
  1256.             /* try with a .zip extension */
  1257.             sprintf (name, "%s/%s.zip", dir_name, gamename);
  1258.             if( cache_stat (name, &stat_buffer) == 0 )
  1259.             {
  1260.                 if( checksum_zipped_file (name, filename, length, sum) == 0 )
  1261.                 {
  1262.                     LOG(("Using (osd_fchecksum) zip file for %s\n", filename));
  1263.                     found = 1;
  1264.                 }
  1265.             }
  1266.         }
  1267.  
  1268.         if( !found )
  1269.         {
  1270.             /* try with a .zif directory (if ZipFolders is installed) */
  1271.             sprintf (name, "%s/%s.zif", dir_name, gamename);
  1272.             if( cache_stat (name, &stat_buffer) == 0 )
  1273.             {
  1274.                 sprintf (name, "%s/%s.zif/%s", dir_name, gamename, filename);
  1275.                 if( checksum_file (name, 0, length, sum) == 0 )
  1276.                 {
  1277.                     found = 1;
  1278.                 }
  1279.             }
  1280.         }
  1281.     }
  1282.  
  1283.     if( !found )
  1284.         return -1;
  1285.  
  1286.     return 0;
  1287. }
  1288.  
  1289. /* JB 980920 */
  1290. int osd_fsize (void *file)
  1291. {
  1292.     FakeFileHandle *f = (FakeFileHandle *) file;
  1293.  
  1294.     if( f->type == kRAMFile || f->type == kZippedFile )
  1295.         return f->length;
  1296.  
  1297.     if( f->file )
  1298.     {
  1299.         int size, offs;
  1300.         offs = ftell( f->file );
  1301.         fseek( f->file, 0, SEEK_END );
  1302.         size = ftell( f->file );
  1303.         fseek( f->file, offs, SEEK_SET );
  1304.         return size;
  1305.     }
  1306.  
  1307.     return 0;
  1308. }
  1309.  
  1310. /* JB 980920 */
  1311. unsigned int osd_fcrc (void *file)
  1312. {
  1313.     FakeFileHandle *f = (FakeFileHandle *) file;
  1314.  
  1315.     return f->crc;
  1316. }
  1317.  
  1318. int osd_fgetc(void *file)
  1319. {
  1320.     FakeFileHandle *f = (FakeFileHandle *) file;
  1321.  
  1322.     if (f->type == kPlainFile && f->file)
  1323.         return fgetc(f->file);
  1324.     else
  1325.         return EOF;
  1326. }
  1327.  
  1328. int osd_ungetc(int c, void *file)
  1329. {
  1330.     FakeFileHandle *f = (FakeFileHandle *) file;
  1331.  
  1332.     if (f->type == kPlainFile && f->file)
  1333.         return ungetc(c,f->file);
  1334.     else
  1335.         return EOF;
  1336. }
  1337.  
  1338. char *osd_fgets(char *s, int n, void *file)
  1339. {
  1340.     FakeFileHandle *f = (FakeFileHandle *) file;
  1341.  
  1342.     if (f->type == kPlainFile && f->file)
  1343.         return fgets(s,n,f->file);
  1344.     else
  1345.         return NULL;
  1346. }
  1347.  
  1348. int osd_feof(void *file)
  1349. {
  1350.     FakeFileHandle *f = (FakeFileHandle *) file;
  1351.  
  1352.     if (f->type == kPlainFile && f->file)
  1353.         return feof(f->file);
  1354.     else
  1355.         return 1;
  1356. }
  1357.  
  1358. int osd_ftell(void *file)
  1359. {
  1360.     FakeFileHandle *f = (FakeFileHandle *) file;
  1361.  
  1362.     if (f->type == kPlainFile && f->file)
  1363.         return ftell(f->file);
  1364.     else
  1365.         return -1L;
  1366. }
  1367.  
  1368.  
  1369. /* called while loading ROMs. It is called a last time with name == 0 to signal */
  1370. /* that the ROM loading process is finished. */
  1371. /* return non-zero to abort loading */
  1372. int osd_display_loading_rom_message (const char *name, int current, int total)
  1373. {
  1374.     if( name )
  1375.         fprintf (stdout, "loading %-12s\r", name);
  1376.     else
  1377.         fprintf (stdout, "                    \r");
  1378.     fflush (stdout);
  1379.  
  1380.     if( keyboard_pressed (KEYCODE_LCONTROL) && keyboard_pressed (KEYCODE_C) )
  1381.         return 1;
  1382.  
  1383.     return 0;
  1384. }
  1385.